1599. Динамическая лягушка
В связи с расширением использования пестицидов, местные ручьи
и реки оказались настолько загрязненными, что стали почти невозможными для
жизни водных животных.
Лягушка Фред находится на левом берегу такой реки. n камней расположено на прямой линии,
простирающейся с левого берега на правый. Расстояние между левым и правым
берегом d метров. Камни могут быть
двух размеров: крупные могут выдержать любой вес, но мелкие начинают тонуть,
как только на них окажется тело любой массы. Фреду нужно перейти на правый
берег, где он должен собрать подарки и вернуться обратно на левый берег в свой
дом.
Фрейд может приземлиться на каждый маленький камень не более
чем один раз. Крупные может использовать столько раз, сколько пожелает. В воду
он прыгнуть не может, так она чрезвычайно загрязнена.
Можете ли вы спланировать маршрут так, чтобы минимизировать
максимальное расстояние одного прыжка?
Вход. Первая строка содержит количество тестов t (t
< 100). Каждый тест начинается двумя целыми числами n (0 ≤ n ≤
100) и d (1 ≤ d ≤ 109). Следующая
строка описывает n камней. Каждый
камень задается в виде s-m. Симол s укзывает на тип камня – Большой (B) или Маленький (S), а m (0 < m < d) определяет
расстояние от этого камня до левого берега. Камни задаются в порядке
возрастания значений m.
Выход. Для каждого теста вывести его номер и минимально
возможное значение наибольшего прыжка.
Пример входа 1 |
Пример выхода 1 |
3 1 10 B-5 1 10 S-5 2 10 B-3 S-6 |
Case 1: 5 Case 2: 10 Case 3: 7 |
|
|
Пример входа 2 |
Пример выхода 2 |
1 6 50 S-2 B-14 S-20 S-26 B-38 S-43 |
Case 1: 18 |
РЕШЕНИЕ
жадный алгоритм
Анализ алгоритма
Очевидно, что на
обратном пути лягушка может использовать все имеющиеся у нее на пути камни. Нам
необходимо разработать стратегию передвижения лягушки с левого берега на правый.
Будем считать, что левый и правый берег являются большими камнями, и изначально
лягушка находится на самом левом камне. Теперь каждый большой камень заменим на
два маленьких, находящихся в одном и том же месте. Это можно сделать, так как
очевидно, что лягушка будет использовать любой большой камень не более двух
раз. Поскольку теперь у нас имеется последовательность только маленьких камней,
то сформулируем алгоритм движения лягушки: при движении с левого на правый
берег она должна каждый раз перепрыгивать через один камень – в этом и состоит
принцип жадного подхода.
Пример
Рассмотрим второй
тест. Переправа содержит n = 6 камней, расстояние между берегами d = 50. Левый и
правый берег представляем большими камнями. Массив и движение лягушки по нем
имеет следующий вид.
Реализация алгоритма
Читаем входные данные.
scanf("%d\n",&tests);
for(t = 1; t <= tests; t++)
{
scanf("%d %d\n",&n,&d);
memset(m,-1,sizeof(m));
Левый
берег представляем одним большим камнем, который заменяем на два маленьких.
m[0] = m[1] = 0;
Считываем
информацию про камни и заполняем массив m. Каждый большой камень заносим в
массив дважды, маленький – только один раз.
for(ptr = 2, i = 0; i < n; i++)
{
do {scanf("%c",&letter);}
while (letter == ' ');
scanf("-%d",&s);
if (letter == 'B')
{m[ptr] = m[ptr+1] = s; ptr += 2;}
else {m[ptr] = s; ptr++;}
}
Правый
берег представляем одним большим камнем, который заменяем на два маленьких.
m[ptr] = m[ptr+1]
= d;
ptr++;
scanf("\n");
Движемся
с самого левого камня до самого правого, перепрыгивая через один. Ищем максимум
разностей между i-ым и (i + 2)-ым камнями.
for(dist = 0, i = 2; i < ptr; i += 2)
if (m[i] - m[i-2] > dist) dist = m[i] - m[i-2];
Уменьшаем
значение i на 1. Теперь движемся справа налево по соседним камням,
которые имеют нечетные номера (камни с четными номерами утонули при движении
лягушки на правый берег).
for(i--; i >= 2; i -= 2)
if (m[i] - m[i-2] > dist) dist = m[i] - m[i-2];
Выводим
ответ.
printf("Case %d: %d\n",t,dist);
}